using System;
using System.Threading;
using Cysharp.Threading.Tasks;

namespace ZYFramework.ObjectPool
{
    /// <summary>
    /// 对象池配置
    /// </summary>
    /// <typeparam name="T">对象类型</typeparam>
    [Serializable]
    public class ObjectPoolConfig<T>
    {
        /// <summary>
        /// 最大容量
        /// 对象池中最多可以存储的对象数量（包括空闲对象和活跃对象）
        /// 当池中对象总数达到此限制时，会根据OverflowPolicy策略处理溢出的对象
        /// </summary>
        /// <remarks>
        /// 容量限制：
        /// - 当对象总数（空闲对象 + 活跃对象）达到MaxCapacity时，新的对象释放操作会触发溢出处理
        /// - 空闲对象数量不能超过MaxCapacity
        /// - 如果活跃对象数量很大，可能会限制新对象的获取
        /// 性能影响：
        /// - 小对象池（MaxCapacity &lt; 阈值）：使用数组存储，查找效率高
        /// - 大对象池（MaxCapacity &gt;= 阈值）：使用分段队列存储，支持优先级管理
        /// 推荐设置：
        /// - 根据实际使用场景和内存限制设置合理的大小
        /// - 太小可能导致频繁创建/销毁对象，影响性能
        /// - 太大可能占用过多内存
        /// 注意事项：
        /// - MaxCapacity必须大于MinCapacity
        /// - 预热数量（PrewarmCount）不能超过MaxCapacity
        /// 默认值：1000
        /// </remarks>
        public int MaxCapacity = 100;

        /// <summary>
        /// 最小保留数量
        /// 对象池在自动回收时会至少保留此数量的空闲对象，低于此数量的对象不会被自动回收
        /// 用于确保对象池中始终保留一定数量的对象，减少频繁创建对象的开销
        /// </summary>
        /// <remarks>
        /// 回收机制：
        /// - 在自动回收（AutoRecycle）时，系统会计算可回收数量：Count - MinCapacity
        /// - 只有当空闲对象数量大于MinCapacity时，才会回收超出部分的对象
        /// - 强制回收（force=true）时，会忽略MinCapacity，回收所有可回收的对象
        /// 使用场景：
        /// - 适合需要保持一定数量预热对象的场景
        /// - 特别适用于创建成本较高的对象（如需要加载资源的GameObject）
        /// - 可以减少对象池为空时的创建延迟
        /// 与MaxCapacity的关系：
        /// - MinCapacity必须小于或等于MaxCapacity
        /// - 建议设置为MaxCapacity的10%-30%
        /// 推荐设置：
        /// - 频繁使用的对象：设置为MaxCapacity的20%-30%
        /// - 偶尔使用的对象：设置为0或MaxCapacity的10%
        /// - 性能敏感场景：可以适当提高MinCapacity
        /// 注意事项：
        /// - MinCapacity只是限制自动回收，不会影响手动回收或Clear()操作
        /// - 设置为0表示不保留对象，所有空闲对象都可能被自动回收
        /// 默认值：0（不保留对象）
        /// </remarks>
        public int MinCapacity = 0;

        /// <summary>
        /// 同步创建函数
        /// 用于创建新对象的同步函数，当对象池中没有可用对象时调用
        /// 如果不设置此函数，默认使用Activator.CreateInstance&lt;T&gt;()创建对象
        /// </summary>
        /// <remarks>
        /// 调用时机：
        /// - 当调用Get()方法时，如果池中没有可用对象，会调用此函数创建新对象
        /// - 在预热（Prewarm）时，会调用此函数创建指定数量的对象
        /// 实现要求：
        /// - 必须返回一个有效的对象实例，不能返回null
        /// - 如果对象创建失败，应该抛出异常而不是返回null
        /// - 创建的对象应该是未激活状态（如果适用）
        /// 使用场景：
        /// - 需要自定义对象创建逻辑时设置此函数
        /// - 例如：从预设实例化GameObject、从工厂模式创建对象、从资源加载等
        /// 注意事项：
        /// - 如果不设置此函数，系统会尝试使用Activator.CreateInstance&lt;T&gt;()创建对象
        /// - 如果T类型没有无参构造函数，必须设置此函数
        /// - 创建函数应该是轻量级的，避免执行耗时操作（如资源加载）
        /// - 耗时操作应该在激活函数（ActivationFunc）中执行
        /// 性能考虑：
        /// - 创建函数的执行时间直接影响Get()方法的性能
        /// - 如果创建成本较高，建议启用预热（PrewarmMode不为Disabled）机制
        /// </remarks>
        public Func<T> CreationFunc_Sync;

        /// <summary>
        /// 异步创建函数
        /// 用于异步创建新对象的函数，当对象池中没有可用对象时异步调用
        /// 适用于需要异步操作来创建对象的场景，如异步加载资源、异步初始化等
        /// </summary>
        /// <param name="cancellationToken">取消令牌，用于取消异步操作</param>
        /// <returns>创建的对象</returns>
        /// <remarks>
        /// 调用时机：
        /// - 当调用GetAsync()方法时，如果池中没有可用对象，会异步调用此函数创建新对象
        /// - 在异步预热时，会异步调用此函数创建指定数量的对象
        /// 执行顺序：
        /// - 优先使用此异步创建函数（如果设置了）
        /// - 如果未设置此函数，会回退到同步创建函数（CreationFunc）
        /// - 创建完成后会调用激活函数（ActivationFuncAsync或ActivationFunc）
        /// 实现要求：
        /// - 必须返回一个有效的对象实例，不能返回null
        /// - 如果对象创建失败，应该抛出异常而不是返回null
        /// - 创建的对象应该是未激活状态（如果适用）
        /// - 应该支持取消令牌（CancellationToken），允许取消正在进行的创建操作
        /// 使用场景：
        /// - 需要异步加载资源来创建对象时使用
        /// - 例如：异步从AssetBundle加载、异步从网络下载、异步初始化复杂对象等
        /// 异常处理：
        /// - 如果此函数抛出异常，GetAsync()会传播异常，不会创建对象
        /// - 建议在函数内部处理可恢复的异常，只抛出致命错误
        /// 性能考虑：
        /// - 异步创建不会阻塞主线程，适合需要耗时操作的场景
        /// - 但需要注意控制并发创建的数量，避免过多的异步操作影响性能
        /// </remarks>
        public Func<CancellationToken, UniTask<T>> CreationFuncAsync;

        /// <summary>
        /// 同步激活函数
        /// 在对象从池中获取时调用，用于激活对象和重置对象状态
        /// 例如：对于GameObject，可以调用SetActive(true)激活对象
        /// </summary>
        /// <remarks>
        /// 调用时机：
        /// - 当从池中取出已存在的对象时，在返回给调用者之前调用
        /// - 当创建新对象时，在对象创建完成后立即调用
        /// 执行顺序：
        /// - 如果设置了此函数，会先调用此函数，然后调用IPoolable.OnGet()（如果对象实现了该接口）
        /// - 如果未设置此函数，则只调用IPoolable.OnGet()（如果对象实现了该接口）
        /// 功能说明：
        /// - 用于激活对象和重置对象状态，使其准备好被使用
        /// - 对于Unity对象（GameObject），通常用于激活对象、重置位置等
        /// - 对于普通C#对象，通常用于重置对象状态、清理临时数据等
        /// 注意事项：
        /// - 此函数应该在对象被使用之前调用，确保对象处于可用状态
        /// - 不应该在此函数中执行耗时操作，耗时操作应该在创建函数中执行
        /// - 如果对象实现了IPoolable接口，此函数会在IPoolable.OnGet()之前调用
        /// </remarks>
        public Action<T> ActivationFunc_Sync;

        /// <summary>
        /// 异步激活函数
        /// 在对象从池中获取时异步调用，用于激活对象和重置对象状态
        /// 例如：对于GameObject，可以异步加载资源后再激活对象
        /// </summary>
        /// <param name="obj">要激活的对象</param>
        /// <param name="cancellationToken">取消令牌，用于取消异步操作</param>
        /// <remarks>
        /// 调用时机：
        /// - 当从池中取出已存在的对象时，在返回给调用者之前异步调用
        /// - 当创建新对象时，在对象创建完成后立即异步调用
        /// 执行顺序：
        /// - 先调用此异步激活函数（如果设置了）
        /// - 如果未设置此函数，会回退到同步激活函数（ActivationFunc）
        /// - 如果对象实现了IAsyncPoolable接口，会在此函数执行后调用OnGetAsync()
        /// 异常处理：
        /// - 如果此函数抛出异常，对象会被放回池中或销毁（取决于是否为新建对象）
        /// </remarks>
        public Func<T, CancellationToken, UniTask> ActivationFunc_Async;

        /// <summary>
        /// 同步回收函数
        /// 在对象返回到池中之前调用，用于清理对象状态和释放资源
        /// 例如：对于GameObject，可以调用SetActive(false)隐藏对象，清理脚本状态等
        /// 如果对象实现了IPoolable接口，会先调用IPoolable.OnReturn()，再调用此函数
        /// </summary>
        /// <remarks>
        /// 调用时机：
        /// - 当对象通过Return()方法返回到池中时，在放入池之前调用
        /// - 当对象池需要清理对象时（如达到最大容量），在对象被销毁或丢弃之前调用
        /// 功能说明：
        /// - 用于重置对象到可重用状态，清理对象上的临时数据和状态
        /// - 与DestroyFunc不同，回收函数只是清理状态，不销毁对象本身
        /// 如果不设置此函数，则只调用IPoolable.OnReturn()（如果对象实现了该接口）
        /// </remarks>
        public Action<T> RecycleFunc_Sync;

        /// <summary>
        /// 异步回收函数
        /// 在对象返回到池中之前异步调用，用于清理对象状态和释放资源
        /// 适用于需要异步操作来清理对象的场景，如异步卸载资源、异步保存数据等
        /// </summary>
        /// <param name="obj">要回收的对象</param>
        /// <param name="cancellationToken">取消令牌，用于取消异步操作</param>
        /// <remarks>
        /// 调用时机：
        /// - 当对象通过ReturnAsync()方法返回到池中时，在放入池之前异步调用
        /// - 当对象池需要清理对象时，在对象被销毁或丢弃之前异步调用
        /// 执行顺序：
        /// - 先调用IPoolable.OnReturn()（如果对象实现了该接口）
        /// - 然后异步调用此函数（如果设置了）
        /// - 如果未设置此函数，会回退到同步回收函数（RecycleFunc）
        /// - 如果对象实现了IAsyncPoolable接口，会在此函数执行后调用OnReturnAsync()
        /// 异常处理：
        /// - 如果此函数抛出异常，对象仍会被放入池中，但可能处于不一致状态
        /// - 建议在函数内部处理异常，确保对象能够正确回收
        /// </remarks>
        public Func<T, CancellationToken, UniTask> RecycleFunc_Async;

        /// <summary>
        /// 同步销毁函数
        /// 在对象从池中永久移除时调用，用于销毁对象和释放所有资源
        /// 例如：对于GameObject，可以调用UnityEngine.Object.Destroy()销毁对象
        /// 对于非Unity对象，可以调用Dispose()或设置为null
        /// </summary>
        /// <remarks>
        /// 调用时机：
        /// - 当对象池达到最大容量且需要强制回收时，会先调用RecycleFunc，然后调用此函数销毁对象
        /// - 当对象池被清空（Clear()）时，对池中的所有对象调用此函数
        /// - 当对象池被销毁时，对池中的所有活跃对象调用此函数
        /// 与RecycleFunc的区别：
        /// - RecycleFunc：清理对象状态，对象仍会保留在池中供后续重用
        /// - DestroyFunc：永久销毁对象，对象从内存中移除，不会再次使用
        /// 如果不设置此函数，系统会使用默认的销毁逻辑（如Object.Destroy对于Unity对象）
        /// </remarks>
        public Action<T> DestroyFunc_Sync;

        /// <summary>
        /// 异步销毁函数
        /// 在对象从池中永久移除时异步调用，用于销毁对象和释放所有资源
        /// 适用于需要异步操作来销毁对象的场景，如异步卸载Asset、异步保存日志等
        /// </summary>
        /// <param name="obj">要销毁的对象</param>
        /// <param name="cancellationToken">取消令牌，用于取消异步操作</param>
        /// <remarks>
        /// 调用时机：
        /// - 当对象池达到最大容量且需要强制回收时，会先调用RecycleFuncAsync，然后异步调用此函数销毁对象
        /// - 当对象池被清空（ClearAsync()）时，对池中的所有对象异步调用此函数
        /// - 当对象池被销毁时，对池中的所有活跃对象异步调用此函数
        /// 执行顺序：
        /// - 先调用RecycleFuncAsync（如果设置了）清理对象状态
        /// - 然后异步调用此函数销毁对象
        /// - 如果未设置此函数，会回退到同步销毁函数（DestroyFunc）
        /// 异常处理：
        /// - 如果此函数抛出异常，对象可能不会被完全销毁
        /// - 建议在函数内部处理异常，确保资源能够正确释放，避免内存泄漏
        /// 性能考虑：
        /// - 异步销毁操作不会阻塞主线程，适合在销毁大量对象时使用
        /// - 但需要注意控制并发销毁的数量，避免过多的异步操作影响性能
        /// </remarks>
        public Func<T, CancellationToken, UniTask> DestroyFunc_Async;

        /// <summary>
        /// 预热数量
        /// 在对象池创建时，预先创建指定数量的对象
        /// 用于提前创建对象，避免在对象池为空时创建对象的延迟
        /// </summary>
        /// <remarks>
        /// 预热机制：
        /// - 在对象池创建时，预先创建指定数量的对象
        /// - 用于提前创建对象，避免在对象池为空时创建对象的延迟
        /// - 预热数量不能超过MaxCapacity
        /// - 预热数量不能小于MinCapacity
        /// </remarks>
        public int PrewarmCount = 0;

        /// <summary>
        /// 是否启用自动回收
        /// 启用后，系统会按照AutoRecycleInterval间隔自动回收空闲对象
        /// 用于定期清理长时间未使用的对象，释放内存并保持对象池的效率
        /// </summary>
        /// <remarks>
        /// 回收机制：
        /// - 当启用时，系统会创建一个后台任务，按照AutoRecycleInterval间隔执行回收
        /// - 回收时会考虑MinCapacity限制，不会回收低于MinCapacity的对象
        /// - 如果启用内存监控，会在内存压力大时触发强制回收
        /// 回收策略：
        /// - 正常回收：回收超出MinCapacity的空闲对象
        /// - 强制回收：在内存压力大时，回收更多对象（可能忽略MinCapacity）
        /// - 回收时会优先回收低优先级的对象（如果支持优先级）
        /// 使用场景：
        /// - 适合需要定期清理空闲对象的场景
        /// - 特别适用于内存敏感的应用或长时间运行的游戏
        /// - 可以配合内存监控使用，在内存压力大时自动清理
        /// 性能影响：
        /// - 自动回收会有轻微的性能开销（定期执行回收操作）
        /// - 但能够及时释放内存，避免内存占用过高
        /// - 回收操作会控制每帧回收数量，避免影响主线程性能
        /// 推荐设置：
        /// - 大多数场景：启用自动回收（默认值）
        /// - 如果对象生命周期可控，可以禁用自动回收，手动控制回收
        /// - 需要与AutoRecycleInterval配合使用，设置合理的回收间隔
        /// 注意事项：
        /// - 自动回收不会影响活跃对象，只回收空闲对象
        /// - 回收间隔应该根据实际使用场景调整，避免过于频繁或过于稀疏
        /// - 如果禁用自动回收，需要手动调用Recycle()方法进行回收
        /// 默认值：true（启用自动回收）
        /// </remarks>
        public bool EnableAutoRecycle = true;

        /// <summary>
        /// 自动回收间隔（秒）
        /// 启用自动回收时，两次回收操作之间的时间间隔
        /// 用于控制自动回收的频率，平衡内存释放和性能开销
        /// </summary>
        /// <remarks>
        /// 间隔说明：
        /// - 单位：秒（float类型，支持小数）
        /// - 系统会按照此间隔定期执行自动回收操作
        /// - 每次回收操作会检查并回收超出MinCapacity的空闲对象
        /// 推荐设置：
        /// - 频繁使用的对象：30-60秒（对象使用频率高，可以更频繁回收）
        /// - 偶尔使用的对象：60-120秒（默认值，适合大多数场景）
        /// - 长时间运行的场景：120-300秒（减少回收频率，避免影响性能）
        /// - 内存敏感场景：30-60秒（更频繁回收，及时释放内存）
        /// 性能影响：
        /// - 间隔过短：回收过于频繁，可能影响性能
        /// - 间隔过长：可能导致内存占用过高，回收不及时
        /// - 需要根据实际使用场景和内存情况调整
        /// 使用场景：
        /// - 需要定期清理空闲对象的场景
        /// - 配合EnableAutoRecycle使用，只有在启用自动回收时才生效
        /// - 可以配合内存监控使用，在内存压力大时会触发额外的强制回收
        /// 注意事项：
        /// - 设置为0或负数会禁用自动回收（等同于EnableAutoRecycle=false）
        /// - 回收操作不会阻塞主线程，使用异步方式执行
        /// - 每次回收会控制每帧回收数量，避免影响游戏性能
        /// 默认值：60f（60秒，1分钟）
        /// </remarks>
        public float AutoRecycleInterval = 60f;
    }
}
